﻿using System;
using System.Linq;
using BusinessBingo.CommandHandlers.Base;
using BusinessBingo.CommandHandlers.Interfaces;
using BusinessBingo.CommandHandlers.Results;
using BusinessBingo.Commands;
using BusinessBingo.Common.Interfaces;
using BusinessBingo.Data.Interfaces;
using BusinessBingo.Model;
using BusinessBingo.Model.Interfaces;

namespace BusinessBingo.CommandHandlers
{
    public class CheckFirstWordInBingoSetAsAnonymousCommandHandler :
        BaseCommandHandler,
        ICheckFirstWordInBingoSetAsAnonymousCommandHandler
    {
        private IGuid _portalGuid;
        private ICreateGroupCommandHandler _createGroupCommandHandler;
        private ICreateNewGameCommandHandler _createNewGameCommandHandler;
        private ICreateUserCommandHandler _createUserCommandHandler;
        private ICreateBingoSetCommandHandler _createBingoSetCommandHandler;

        public CheckFirstWordInBingoSetAsAnonymousCommandHandler(
            IGuid portalGuid,
            IValidationState validationState,
            IUnitOfWork unitOfWork,
            ICreateGroupCommandHandler createGroupCommandHandler,
            ICreateNewGameCommandHandler createNewGameCommandHandler,
            ICreateUserCommandHandler createUserCommandHandler,
            ICreateBingoSetCommandHandler createBingoSetCommandHandler
            )
            : base(validationState, unitOfWork)
        {
            this._portalGuid = portalGuid;
            this._createGroupCommandHandler = createGroupCommandHandler;
            this._createNewGameCommandHandler = createNewGameCommandHandler;
            this._createUserCommandHandler = createUserCommandHandler;
            this._createBingoSetCommandHandler = createBingoSetCommandHandler;
        }

        public CheckFirstWordInBingoSetAsAnonymousCommandHandlerResult Execute(CheckFirstWordInBingoSetAsAnonymousCommand checkFirstWordInBingoSetAsAnonymousCommand)
        {
            CheckFirstWordInBingoSetAsAnonymousCommandHandlerResult result =
                new CheckFirstWordInBingoSetAsAnonymousCommandHandlerResult();

            if(checkFirstWordInBingoSetAsAnonymousCommand == default(CheckFirstWordInBingoSetAsAnonymousCommand))
                throw new ArgumentNullException("CheckFirstWordInBingoSetAsAnonymousCommand");
            if(checkFirstWordInBingoSetAsAnonymousCommand.BingoSet == default(BingoSet))
                this._validationState.AddError<CheckFirstWordInBingoSetAsAnonymousCommand>(x => x.BingoSet, ErrorTypes.Empty);
            if(checkFirstWordInBingoSetAsAnonymousCommand.WordId == default(Guid))
                this._validationState.AddError<CheckFirstWordInBingoSetAsAnonymousCommand>(x => x.WordId, ErrorTypes.Empty);

            if (this._validationState.IsValid == false) return result;

            string userName = this._portalGuid.New.ToString();

            CreateGroupCommand createGroupCommand = new CreateGroupCommand(this._portalGuid.New.ToString(),
                                                                           checkFirstWordInBingoSetAsAnonymousCommand.
                                                                               BingoSet.Language);
            CreateGroupCommandHandlerResult createGroupCommandResult = this._createGroupCommandHandler.Execute(createGroupCommand);
            if (createGroupCommandResult.Succeeded == false) return result;

            CreateNewGameCommand createNewGameCommand = new CreateNewGameCommand(createGroupCommandResult.Group.Id);
            CreateNewGameCommandHandlerResult createNewGameCommandHandlerResult = this._createNewGameCommandHandler.Execute(createNewGameCommand);
            if (createNewGameCommandHandlerResult.Succeeded == false) return result;
            
            CreateUserCommand createUserCommand = new CreateUserCommand(userName, createGroupCommandResult.Group.Id);
            CreateUserCommandHandlerResult createUserCommandResult =
                this._createUserCommandHandler.Execute(createUserCommand);
            if (createUserCommandResult.Succeeded == false) return result;

            checkFirstWordInBingoSetAsAnonymousCommand.BingoSet.WordPositions.Where(
                x => x.Word.Id.Equals(checkFirstWordInBingoSetAsAnonymousCommand.WordId)).Single().Checked = true;

            CreateBingoSetCommand createBingoSetCommand =
                new CreateBingoSetCommand(checkFirstWordInBingoSetAsAnonymousCommand.BingoSet,
                                          createNewGameCommandHandlerResult.Game.Id,
                                          createUserCommandResult.User.Id);
            CreateBingoSetCommandHandlerResult createBingoSetCommandResult =
                this._createBingoSetCommandHandler.Execute(createBingoSetCommand);
            if (createBingoSetCommandResult.Succeeded == false) return result;

            base.Complete();

            result.Succeeded = true;
            result.UserId = createUserCommandResult.User.Id;
            result.GameId = createNewGameCommandHandlerResult.Game.Id;

            return result;
        }
    }
}